Load the FW functions
### CODE DIRECTLY FROM: https://burtmonroe.github.io/TextAsDataCourse/Tutorials/TADA-FightinWords.nb.html#
fwgroups <- function(dtm, groups, pair = NULL, weights = rep(1,nrow(dtm)), k.prior = .1) {
weights[is.na(weights)] <- 0
weights <- weights/mean(weights)
zero.doc <- rowSums(dtm)==0 | weights==0
zero.term <- colSums(dtm[!zero.doc,])==0
dtm.nz <- apply(dtm[!zero.doc,!zero.term],2,"*", weights[!zero.doc])
g.prior <- tcrossprod(rowSums(dtm.nz),colSums(dtm.nz))/sum(dtm.nz)
#
g.posterior <- as.matrix(dtm.nz + k.prior*g.prior)
groups <- groups[!zero.doc]
groups <- droplevels(groups)
g.adtm <- as.matrix(aggregate(x=g.posterior,by=list(groups=groups),FUN=sum)[,-1])
rownames(g.adtm) <- levels(groups)
g.ladtm <- log(g.adtm)
g.delta <- t(scale( t(scale(g.ladtm, center=T, scale=F)), center=T, scale=F))
g.adtm_w <- -sweep(g.adtm,1,rowSums(g.adtm)) # terms not w spoken by k
g.adtm_k <- -sweep(g.adtm,2,colSums(g.adtm)) # w spoken by groups other than k
g.adtm_kw <- sum(g.adtm) - g.adtm_w - g.adtm_k - g.adtm # total terms not w or k
g.se <- sqrt(1/g.adtm + 1/g.adtm_w + 1/g.adtm_k + 1/g.adtm_kw)
g.zeta <- g.delta/g.se
g.counts <- as.matrix(aggregate(x=dtm.nz, by = list(groups=groups), FUN=sum)[,-1])
if (!is.null(pair)) {
pr.delta <- t(scale( t(scale(g.ladtm[pair,], center = T, scale =F)), center=T, scale=F))
pr.adtm_w <- -sweep(g.adtm[pair,],1,rowSums(g.adtm[pair,]))
pr.adtm_k <- -sweep(g.adtm[pair,],2,colSums(g.adtm[pair,])) # w spoken by groups other than k
pr.adtm_kw <- sum(g.adtm[pair,]) - pr.adtm_w - pr.adtm_k - g.adtm[pair,] # total terms not w or k
pr.se <- sqrt(1/g.adtm[pair,] + 1/pr.adtm_w + 1/pr.adtm_k + 1/pr.adtm_kw)
pr.zeta <- pr.delta/pr.se
return(list(zeta=pr.zeta[1,], delta=pr.delta[1,],se=pr.se[1,], counts = colSums(dtm.nz), acounts = colSums(g.adtm)))
} else {
return(list(zeta=g.zeta,delta=g.delta,se=g.se,counts=g.counts,acounts=g.adtm))
}
}
############## FIGHTIN' WORDS PLOTTING FUNCTION
# helper function
makeTransparent<-function(someColor, alpha=100)
{
newColor<-col2rgb(someColor)
apply(newColor, 2, function(curcoldata){rgb(red=curcoldata[1], green=curcoldata[2],
blue=curcoldata[3],alpha=alpha, maxColorValue=255)})
}
fw.ggplot.groups <- function(fw.ch, groups.use = as.factor(rownames(fw.ch$zeta)), max.words = 50, max.countrank = 400, colorpalette=rep("black",length(groups.use)), sizescale=2, title="Comparison of Terms by Groups", subtitle = "", caption = "Group-specific terms are ordered by Fightin' Words statistic (Monroe, et al. 2008)") {
if (is.null(dim(fw.ch$zeta))) {## two-group fw object consists of vectors, not matrices
zetarankmat <- cbind(rank(-fw.ch$zeta),rank(fw.ch$zeta))
colnames(zetarankmat) <- groups.use
countrank <- rank(-(fw.ch$counts))
} else {
zetarankmat <- apply(-fw.ch$zeta[groups.use,],1,rank)
countrank <- rank(-colSums(fw.ch$counts))
}
wideplotmat <- as_tibble(cbind(zetarankmat,countrank=countrank))
wideplotmat$term=names(countrank)
rankplot <- gather(wideplotmat, groups.use, zetarank, 1:ncol(zetarankmat))
rankplot$plotsize <- sizescale*(50/(rankplot$zetarank))^(1/4)
rankplot <- rankplot[rankplot$zetarank < max.words + 1 & rankplot$countrank<max.countrank+1,]
rankplot$groups.use <- factor(rankplot$groups.use,levels=groups.use)
p <- ggplot(rankplot, aes((nrow(rankplot)-countrank)^1, -(zetarank^1), colour=groups.use)) +
geom_point(show.legend=F,size=sizescale/2) +
theme_classic() +
theme(axis.ticks=element_blank(), axis.text=element_blank() ) +
ylim(-max.words,40) +
facet_grid(groups.use ~ .) +
geom_text_repel(aes(label = term), size = rankplot$plotsize, point.padding=.05,
box.padding = unit(0.20, "lines"), show.legend=F) +
scale_colour_manual(values = alpha(colorpalette, .7)) +
labs(x=paste("Terms used more frequently overall -->"), y=paste("Terms used more frequently by group -->"), title=title, subtitle=subtitle , caption = caption)
}
fw.keys <- function(fw.ch,n.keys=10) {
n.groups <- nrow(fw.ch$zeta)
keys <- matrix("",n.keys,n.groups)
colnames(keys) <- rownames(fw.ch$zeta)
for (g in 1:n.groups) {
keys[,g] <- names(sort(fw.ch$zeta[g,],dec=T)[1:n.keys])
}
keys
}
Compare Associated Press 1994-2010: Before and After “extremist”
Load and clean the data
- to string & lower text
- pivot to long format
- apply text_cleaner to one column “context.text”
######################################
### Text Cleaning Function
text_cleaner<-function(corpus){
tempcorpus<-Corpus(VectorSource(corpus))
tempcorpus<-tm_map(tempcorpus,
removePunctuation)
tempcorpus<-tm_map(tempcorpus,
stripWhitespace)
tempcorpus<-tm_map(tempcorpus,
removeNumbers)
tempcorpus<-tm_map(tempcorpus,
removeWords, stopwords("english"))
tempcorpus<-tm_map(tempcorpus,
stemDocument)
return(tempcorpus)
}
######################################
Calculate FW.
[1] 0.9900516
##################################################################
fw.extrem <- fwgroups(extrem_dtm, groups=extrem_NYT.dfm.long$Context)
Error: vector memory exhausted (limit reached?)
Get and show the top words per group by zeta.
##################################################################
fwkeys.extrem <- fw.keys(fw.extrem, n.keys=20)
cols <- rev(colnames(fwkeys.extrem))
fwkeys.extrem <- fwkeys.extrem[,cols]
##################################################################
kable(fwkeys.extrem)
| muslim |
group |
| jewish |
organ |
| rightw |
movement |
| islamic |
respons |
| member |
element |
| rrb |
hutu |
| suspect |
network |
| belong |
ideolog |
| ban |
militia |
| lrb |
oppos |
| alqaidalink |
view |
| small |
activ |
| rabin |
bomb |
| sunni |
sayyaf |
| assassin |
threaten |
| ap |
parti |
| alleg |
abu |
| outlaw |
attack |
| yitzhak |
alqaida |
| help |
govern |
##################################################################
Plot: Comparing Words Before (in Blue), and After (in Red)
p.fw.extrem <- fw.ggplot.groups(fw.extrem,sizescale=4,max.words=200,
max.countrank=400,colorpalette=c("red","blue"),
title = 'Comparison of Terms Before and After "Extremist"')
p.fw.extrem

Extrem(ist) Fightin’ Words Over Time
library(tweenr)
TransitionTime2 <- ggproto(
"TransitionTime2",
TransitionTime,
expand_panel = function (self, data, type, id, match, ease, enter, exit, params,
layer_index) {
row_time <- self$get_row_vars(data)
if (is.null(row_time))
return(data)
data$group <- paste0(row_time$before, row_time$after)
time <- as.integer(row_time$time)
states <- split(data, time)
times <- as.integer(names(states))
nframes <- diff(times)
nframes[1] <- nframes[1] + 1
if (times[1] <= 1) {
all_frames <- states[[1]]
states <- states[-1]
}
else {
all_frames <- data[0, , drop = FALSE]
nframes <- c(times[1] - 1, nframes)
}
if (times[length(times)] < params$nframes) {
states <- c(states, list(data[0, , drop = FALSE]))
nframes <- c(nframes, params$nframes - times[length(times)])
}
for (i in seq_along(states)) {
all_frames <- switch(type, point = tween_state(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit),
path = transform_path(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit, match),
polygon = transform_polygon(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit, match),
sf = transform_sf(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit),
stop(type,
" layers not currently supported by transition_time",
call. = FALSE))
}
true_frame <- seq(times[1], times[length(times)])
all_frames <- all_frames[
all_frames$.frame %in%
# which(true_frame > 0 & true_frame <= params$nframes),
true_frame[which(true_frame > 0 & true_frame <= params$nframes)], # tweak line A
,
drop = FALSE]
# all_frames$.frame <- all_frames$.frame - min(all_frames$.frame) + 1 # remove line B
all_frames$group <- paste0(all_frames$group, "<", all_frames$.frame, ">")
all_frames$.frame <- NULL
all_frames
})
transition_time2 <- function (time, range = NULL) {
time_quo <- enquo(time)
gganimate:::require_quo(time_quo, "time")
ggproto(NULL, TransitionTime2,
params = list(time_quo = time_quo, range = range))
}
cooc_year<- data.frame()
for(y in unique(results_odd.before$pubyear)){
print(y)
cooc <- cooccurrence(x = subset(filter(results_odd.before, pubyear == y), upos %in% c("NOUN", "ADJ")),
term = "lemma",
group = c("doc_id", "paragraph_id", "sentence_id"))
cooc$year <- y
cooc<- head(cooc, 14)
cooc_year <- rbind(cooc_year, cooc)
}
[1] 1994
[1] 1995
[1] 1996
[1] 1997
[1] 1998
[1] 1999
[1] 2000
[1] 2001
[1] 2002
[1] 2003
[1] 2004
[1] 2005
[1] 2006
[1] 2007
[1] 2008
[1] 2009
[1] 2010
[1] 238 4
wordnetwork <- cooc_year
p<- ggraph(wordnetwork, layout = "fr") +
geom_edge_link(aes(width = cooc, edge_alpha = cooc), edge_colour = "pink") +
geom_node_text(aes(label = name), col = "darkgreen", size = 4) +
theme_graph(base_family = "Arial Narrow") +
theme(legend.position = "none") +
# facet_wrap_paginate(~year)+
scale_alpha_identity()+
labs(title = "Cooccurrences within sentence: BEFORE", subtitle = "Nouns & Adjective {frame_time}")+
transition_time2(year)
ease_aes('linear')
<ggproto object: Class EaseAes, gg>
aes_names:
aesthetics:
default: linear
get_ease: function
super: <ggproto object: Class EaseAes, gg>
cooc_year<- data.frame()
for(y in unique(results_even.after$pubyear)){
print(y)
cooc <- cooccurrence(x = subset(filter(results_even.after, pubyear == y), upos %in% c("NOUN", "ADJ")),
term = "lemma",
group = c("doc_id", "paragraph_id", "sentence_id"))
cooc$year <- y
cooc<- head(cooc, 14)
cooc_year <- rbind(cooc_year, cooc)
}
[1] 1994
[1] 1995
[1] 1996
[1] 1997
[1] 1998
[1] 1999
[1] 2000
[1] 2001
[1] 2002
[1] 2003
[1] 2004
[1] 2005
[1] 2006
[1] 2007
[1] 2008
[1] 2009
[1] 2010
[1] 238 4
wordnetwork <- cooc_year
p2<- ggraph(wordnetwork, layout = "fr") +
geom_edge_link(aes(width = cooc, edge_alpha = cooc), edge_colour = "pink") +
geom_node_text(aes(label = name), col = "darkgreen", size = 4) +
theme_graph(base_family = "Arial Narrow") +
theme(legend.position = "none") +
# facet_wrap_paginate(~year)+
scale_alpha_identity()+
labs(title = "Cooccurrences within sentence: AFTER", subtitle = "Nouns & Adjective {frame_time}")+
transition_time2(year)
ease_aes('linear')
<ggproto object: Class EaseAes, gg>
aes_names:
aesthetics:
default: linear
get_ease: function
super: <ggproto object: Class EaseAes, gg>
Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!


cooc2_year<- data.frame()
for(y in unique(results_odd.before$pubyear)){
print(y)
a<- filter(results_odd.before, pubyear == y)
cooc <- cooccurrence(a$lemma, relevant = a$upos %in% c("NOUN", "ADJ"), skipgram = 1)
cooc$year <- y
cooc<- head(cooc, 25)
cooc2_year <- rbind(cooc2_year, cooc)
}
[1] 1994
[1] 1995
[1] 1996
[1] 1997
[1] 1998
[1] 1999
[1] 2000
[1] 2001
[1] 2002
[1] 2003
[1] 2004
[1] 2005
[1] 2006
[1] 2007
[1] 2008
[1] 2009
[1] 2010
[1] 425 4
wordnetwork <- cooc2_year
p3<- ggraph(wordnetwork, layout = "fr") +
geom_edge_link(aes(width = cooc, edge_alpha = cooc), edge_colour = "pink") +
geom_node_text(aes(label = name), col = "darkgreen", size = 4) +
theme_graph(base_family = "Arial Narrow") +
theme(legend.position = "none") +
# facet_wrap_paginate(~year)+
scale_alpha_identity()+
labs(title = "Cooccurrences within sentence: BEFORE", subtitle = "Nouns & Adjective {frame_time}")+
transition_time2(year)
ease_aes('linear')
<ggproto object: Class EaseAes, gg>
aes_names:
aesthetics:
default: linear
get_ease: function
super: <ggproto object: Class EaseAes, gg>
Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!


cooc2_year<- data.frame()
for(y in unique(results_even.after$pubyear)){
print(y)
a<- filter(results_even.after, pubyear == y)
cooc <- cooccurrence(a$lemma, relevant = a$upos %in% c("NOUN", "ADJ"), skipgram = 1)
cooc$year <- y
cooc<- head(cooc, 25)
cooc2_year <- rbind(cooc2_year, cooc)
}
[1] 1994
[1] 1995
[1] 1996
[1] 1997
[1] 1998
[1] 1999
[1] 2000
[1] 2001
[1] 2002
[1] 2003
[1] 2004
[1] 2005
[1] 2006
[1] 2007
[1] 2008
[1] 2009
[1] 2010
[1] 425 4
wordnetwork <- cooc2_year
p4<- ggraph(wordnetwork, layout = "fr") +
geom_edge_link(aes(width = cooc, edge_alpha = cooc), edge_colour = "pink") +
geom_node_text(aes(label = name), col = "darkgreen", size = 4) +
theme_graph(base_family = "Arial Narrow") +
theme(legend.position = "none") +
# facet_wrap_paginate(~year)+
scale_alpha_identity()+
labs(title = "Cooccurrences within sentence: AFTER", subtitle = "Nouns & Adjective {frame_time}")+
transition_time2(year)
ease_aes('linear')
<ggproto object: Class EaseAes, gg>
aes_names:
aesthetics:
default: linear
get_ease: function
super: <ggproto object: Class EaseAes, gg>
Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!


home
LS0tCnRpdGxlOiAiRXh0cmVtKGlzdCkgRmlnaHRpbicgV29yZHMiCmF1dGhvcjogIkJyZWFubmEgRS4gR3JlZW4iCnN1YnRpdGxlOiAnQXNzb2NpYXRlZCBQcmVzcyAxOTk0LTIwMTA6IEtleXdvcmQ6IkV4dHJlbWlzdCInCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB5ZXMKLS0tCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQoKIyMgTG9hZCBMaWJyYXJpZXMKCmBgYHtyIGxvYWQgbGlicmFyaWVzLCByZXN1bHRzPSdoaWRlJ30KCiMjIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdWRwaXBlL3ZpZ25ldHRlcy91ZHBpcGUtdXNlY2FzZS1wb3N0YWdnaW5nLWxlbW1hdGlzYXRpb24uaHRtbApsaWJyYXJ5KHVkcGlwZSkKdWRfbW9kZWwgPC0gdWRwaXBlX2Rvd25sb2FkX21vZGVsKGxhbmd1YWdlID0gImVuZ2xpc2giKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KGxhdHRpY2UpCmxpYnJhcnkobGF0dGljZUV4dHJhKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShwZHApCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCmBgYAoKIyMgTG9hZCB0aGUgRlcgZnVuY3Rpb25zCgpgYGB7ciBsb2FkX2Z3X2Z1bmN0aW9uc30KCiMjIyBDT0RFIERJUkVDVExZIEZST006IGh0dHBzOi8vYnVydG1vbnJvZS5naXRodWIuaW8vVGV4dEFzRGF0YUNvdXJzZS9UdXRvcmlhbHMvVEFEQS1GaWdodGluV29yZHMubmIuaHRtbCMKZndncm91cHMgPC0gZnVuY3Rpb24oZHRtLCBncm91cHMsIHBhaXIgPSBOVUxMLCB3ZWlnaHRzID0gcmVwKDEsbnJvdyhkdG0pKSwgay5wcmlvciA9IC4xKSB7CiAgCiAgd2VpZ2h0c1tpcy5uYSh3ZWlnaHRzKV0gPC0gMAogIAogIHdlaWdodHMgPC0gd2VpZ2h0cy9tZWFuKHdlaWdodHMpCiAgCiAgemVyby5kb2MgPC0gcm93U3VtcyhkdG0pPT0wIHwgd2VpZ2h0cz09MAogIHplcm8udGVybSA8LSBjb2xTdW1zKGR0bVshemVyby5kb2MsXSk9PTAKICAKICBkdG0ubnogPC0gYXBwbHkoZHRtWyF6ZXJvLmRvYywhemVyby50ZXJtXSwyLCIqIiwgd2VpZ2h0c1shemVyby5kb2NdKQogIAogIGcucHJpb3IgPC0gdGNyb3NzcHJvZChyb3dTdW1zKGR0bS5ueiksY29sU3VtcyhkdG0ubnopKS9zdW0oZHRtLm56KQogIAogICMgCiAgCiAgZy5wb3N0ZXJpb3IgPC0gYXMubWF0cml4KGR0bS5ueiArIGsucHJpb3IqZy5wcmlvcikKICAKICBncm91cHMgPC0gZ3JvdXBzWyF6ZXJvLmRvY10KICBncm91cHMgPC0gZHJvcGxldmVscyhncm91cHMpCiAgCiAgZy5hZHRtIDwtIGFzLm1hdHJpeChhZ2dyZWdhdGUoeD1nLnBvc3RlcmlvcixieT1saXN0KGdyb3Vwcz1ncm91cHMpLEZVTj1zdW0pWywtMV0pCiAgcm93bmFtZXMoZy5hZHRtKSA8LSBsZXZlbHMoZ3JvdXBzKQogIAogIGcubGFkdG0gPC0gbG9nKGcuYWR0bSkKICAKICBnLmRlbHRhIDwtIHQoc2NhbGUoIHQoc2NhbGUoZy5sYWR0bSwgY2VudGVyPVQsIHNjYWxlPUYpKSwgY2VudGVyPVQsIHNjYWxlPUYpKQogIAogIGcuYWR0bV93IDwtIC1zd2VlcChnLmFkdG0sMSxyb3dTdW1zKGcuYWR0bSkpICMgdGVybXMgbm90IHcgc3Bva2VuIGJ5IGsKICBnLmFkdG1fayA8LSAtc3dlZXAoZy5hZHRtLDIsY29sU3VtcyhnLmFkdG0pKSAjIHcgc3Bva2VuIGJ5IGdyb3VwcyBvdGhlciB0aGFuIGsKICBnLmFkdG1fa3cgPC0gc3VtKGcuYWR0bSkgLSBnLmFkdG1fdyAtIGcuYWR0bV9rIC0gZy5hZHRtICMgdG90YWwgdGVybXMgbm90IHcgb3IgayAKICAKICBnLnNlIDwtIHNxcnQoMS9nLmFkdG0gKyAxL2cuYWR0bV93ICsgMS9nLmFkdG1fayArIDEvZy5hZHRtX2t3KQogIAogIGcuemV0YSA8LSBnLmRlbHRhL2cuc2UKICAKICBnLmNvdW50cyA8LSBhcy5tYXRyaXgoYWdncmVnYXRlKHg9ZHRtLm56LCBieSA9IGxpc3QoZ3JvdXBzPWdyb3VwcyksIEZVTj1zdW0pWywtMV0pCiAgCiAgaWYgKCFpcy5udWxsKHBhaXIpKSB7CiAgICBwci5kZWx0YSA8LSB0KHNjYWxlKCB0KHNjYWxlKGcubGFkdG1bcGFpcixdLCBjZW50ZXIgPSBULCBzY2FsZSA9RikpLCBjZW50ZXI9VCwgc2NhbGU9RikpCiAgICBwci5hZHRtX3cgPC0gLXN3ZWVwKGcuYWR0bVtwYWlyLF0sMSxyb3dTdW1zKGcuYWR0bVtwYWlyLF0pKQogICAgcHIuYWR0bV9rIDwtIC1zd2VlcChnLmFkdG1bcGFpcixdLDIsY29sU3VtcyhnLmFkdG1bcGFpcixdKSkgIyB3IHNwb2tlbiBieSBncm91cHMgb3RoZXIgdGhhbiBrCiAgICBwci5hZHRtX2t3IDwtIHN1bShnLmFkdG1bcGFpcixdKSAtIHByLmFkdG1fdyAtIHByLmFkdG1fayAtIGcuYWR0bVtwYWlyLF0gIyB0b3RhbCB0ZXJtcyBub3QgdyBvciBrCiAgICBwci5zZSA8LSBzcXJ0KDEvZy5hZHRtW3BhaXIsXSArIDEvcHIuYWR0bV93ICsgMS9wci5hZHRtX2sgKyAxL3ByLmFkdG1fa3cpCiAgICBwci56ZXRhIDwtIHByLmRlbHRhL3ByLnNlCiAgICAKICAgIHJldHVybihsaXN0KHpldGE9cHIuemV0YVsxLF0sIGRlbHRhPXByLmRlbHRhWzEsXSxzZT1wci5zZVsxLF0sIGNvdW50cyA9IGNvbFN1bXMoZHRtLm56KSwgYWNvdW50cyA9IGNvbFN1bXMoZy5hZHRtKSkpCiAgfSBlbHNlIHsKICAgIHJldHVybihsaXN0KHpldGE9Zy56ZXRhLGRlbHRhPWcuZGVsdGEsc2U9Zy5zZSxjb3VudHM9Zy5jb3VudHMsYWNvdW50cz1nLmFkdG0pKQogIH0KfQoKIyMjIyMjIyMjIyMjIyMgRklHSFRJTicgV09SRFMgUExPVFRJTkcgRlVOQ1RJT04KCiMgaGVscGVyIGZ1bmN0aW9uCm1ha2VUcmFuc3BhcmVudDwtZnVuY3Rpb24oc29tZUNvbG9yLCBhbHBoYT0xMDApCnsKICBuZXdDb2xvcjwtY29sMnJnYihzb21lQ29sb3IpCiAgYXBwbHkobmV3Q29sb3IsIDIsIGZ1bmN0aW9uKGN1cmNvbGRhdGEpe3JnYihyZWQ9Y3VyY29sZGF0YVsxXSwgZ3JlZW49Y3VyY29sZGF0YVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsdWU9Y3VyY29sZGF0YVszXSxhbHBoYT1hbHBoYSwgbWF4Q29sb3JWYWx1ZT0yNTUpfSkKfQoKZncuZ2dwbG90Lmdyb3VwcyA8LSBmdW5jdGlvbihmdy5jaCwgZ3JvdXBzLnVzZSA9IGFzLmZhY3Rvcihyb3duYW1lcyhmdy5jaCR6ZXRhKSksIG1heC53b3JkcyA9IDUwLCBtYXguY291bnRyYW5rID0gNDAwLCBjb2xvcnBhbGV0dGU9cmVwKCJibGFjayIsbGVuZ3RoKGdyb3Vwcy51c2UpKSwgc2l6ZXNjYWxlPTIsIHRpdGxlPSJDb21wYXJpc29uIG9mIFRlcm1zIGJ5IEdyb3VwcyIsIHN1YnRpdGxlID0gIiIsIGNhcHRpb24gPSAiR3JvdXAtc3BlY2lmaWMgdGVybXMgYXJlIG9yZGVyZWQgYnkgRmlnaHRpbicgV29yZHMgc3RhdGlzdGljIChNb25yb2UsIGV0IGFsLiAyMDA4KSIpIHsKICBpZiAoaXMubnVsbChkaW0oZncuY2gkemV0YSkpKSB7IyMgdHdvLWdyb3VwIGZ3IG9iamVjdCBjb25zaXN0cyBvZiB2ZWN0b3JzLCBub3QgbWF0cmljZXMKICAgIHpldGFyYW5rbWF0IDwtIGNiaW5kKHJhbmsoLWZ3LmNoJHpldGEpLHJhbmsoZncuY2gkemV0YSkpCiAgICBjb2xuYW1lcyh6ZXRhcmFua21hdCkgPC0gZ3JvdXBzLnVzZQogICAgY291bnRyYW5rIDwtIHJhbmsoLShmdy5jaCRjb3VudHMpKQogIH0gZWxzZSB7CiAgICB6ZXRhcmFua21hdCA8LSBhcHBseSgtZncuY2gkemV0YVtncm91cHMudXNlLF0sMSxyYW5rKQogICAgY291bnRyYW5rIDwtIHJhbmsoLWNvbFN1bXMoZncuY2gkY291bnRzKSkKICB9CiAgd2lkZXBsb3RtYXQgPC0gYXNfdGliYmxlKGNiaW5kKHpldGFyYW5rbWF0LGNvdW50cmFuaz1jb3VudHJhbmspKQogIHdpZGVwbG90bWF0JHRlcm09bmFtZXMoY291bnRyYW5rKQogIHJhbmtwbG90IDwtIGdhdGhlcih3aWRlcGxvdG1hdCwgZ3JvdXBzLnVzZSwgemV0YXJhbmssIDE6bmNvbCh6ZXRhcmFua21hdCkpCiAgcmFua3Bsb3QkcGxvdHNpemUgPC0gc2l6ZXNjYWxlKig1MC8ocmFua3Bsb3QkemV0YXJhbmspKV4oMS80KQogIHJhbmtwbG90IDwtIHJhbmtwbG90W3JhbmtwbG90JHpldGFyYW5rIDwgbWF4LndvcmRzICsgMSAmIHJhbmtwbG90JGNvdW50cmFuazxtYXguY291bnRyYW5rKzEsXQogIHJhbmtwbG90JGdyb3Vwcy51c2UgPC0gZmFjdG9yKHJhbmtwbG90JGdyb3Vwcy51c2UsbGV2ZWxzPWdyb3Vwcy51c2UpCiAgCiAgcCA8LSBnZ3Bsb3QocmFua3Bsb3QsIGFlcygobnJvdyhyYW5rcGxvdCktY291bnRyYW5rKV4xLCAtKHpldGFyYW5rXjEpLCBjb2xvdXI9Z3JvdXBzLnVzZSkpICsgCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kPUYsc2l6ZT1zaXplc2NhbGUvMikgKyAKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0PWVsZW1lbnRfYmxhbmsoKSApICsKICAgIHlsaW0oLW1heC53b3Jkcyw0MCkgKwogICAgZmFjZXRfZ3JpZChncm91cHMudXNlIH4gLikgKwogICAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHRlcm0pLCBzaXplID0gcmFua3Bsb3QkcGxvdHNpemUsIHBvaW50LnBhZGRpbmc9LjA1LAogICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gdW5pdCgwLjIwLCAibGluZXMiKSwgc2hvdy5sZWdlbmQ9RikgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbHBoYShjb2xvcnBhbGV0dGUsIC43KSkgKyAKICAgIGxhYnMoeD1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgb3ZlcmFsbCAtLT4iKSwgeT1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgYnkgZ3JvdXAgLS0+IiksICB0aXRsZT10aXRsZSwgc3VidGl0bGU9c3VidGl0bGUgLCBjYXB0aW9uID0gY2FwdGlvbikgCiAgCn0KCmZ3LmtleXMgPC0gZnVuY3Rpb24oZncuY2gsbi5rZXlzPTEwKSB7CiAgbi5ncm91cHMgPC0gbnJvdyhmdy5jaCR6ZXRhKQogIGtleXMgPC0gbWF0cml4KCIiLG4ua2V5cyxuLmdyb3VwcykKICBjb2xuYW1lcyhrZXlzKSA8LSByb3duYW1lcyhmdy5jaCR6ZXRhKQogIAogIGZvciAoZyBpbiAxOm4uZ3JvdXBzKSB7CiAgICBrZXlzWyxnXSA8LSBuYW1lcyhzb3J0KGZ3LmNoJHpldGFbZyxdLGRlYz1UKVsxOm4ua2V5c10pCiAgfQogIGtleXMKfQpgYGAKCgojIyBDb21wYXJlIEFzc29jaWF0ZWQgUHJlc3MgMTk5NC0yMDEwOiBCZWZvcmUgYW5kIEFmdGVyICJleHRyZW1pc3QiCgoqTG9hZCBhbmQgY2xlYW4gdGhlIGRhdGEqCgogICogdG8gc3RyaW5nICYgbG93ZXIgdGV4dAogICogcGl2b3QgdG8gbG9uZyBmb3JtYXQKICAqIGFwcGx5IHRleHRfY2xlYW5lciB0byBvbmUgY29sdW1uICJjb250ZXh0LnRleHQiCgpgYGB7cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIyMgVGV4dCBDbGVhbmluZyBGdW5jdGlvbgoKdGV4dF9jbGVhbmVyPC1mdW5jdGlvbihjb3JwdXMpewogIHRlbXBjb3JwdXM8LUNvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICByZW1vdmVQdW5jdHVhdGlvbikKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICBzdHJpcFdoaXRlc3BhY2UpCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTnVtYmVycykKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQogIHRlbXBjb3JwdXM8LXRtX21hcCh0ZW1wY29ycHVzLCAKICAgICAgICAgICAgICAgICAgICBzdGVtRG9jdW1lbnQpCiAgcmV0dXJuKHRlbXBjb3JwdXMpCn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCmBgYHtyIGNsZWFuX3RleHQsIGVjaG89RkFMU0UsIHJlc3VsdHM9IEZBTFNFfQoKZXh0cmVtX0FQLmRmbSA8LSByZWFkLmRlbGltKCJleHRyZW1pc3RfOTQxMF9BUC50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQpleHRyZW1fQVAuZGZtJHB1YmRhdGUgPSBzdWJzdHIoZXh0cmVtX0FQLmRmbSRUZXh0LklELDksMTYpCmV4dHJlbV9BUC5kZm0kcHViZGF0ZSA8LSBhcy5QT1NJWGN0KGV4dHJlbV9BUC5kZm0kcHViZGF0ZSwgZm9ybWF0ID0gIiVZJW0lZCIpCmV4dHJlbV9BUC5kZm0kcHViZGF0ZSA8LSBhcy5EYXRlKGV4dHJlbV9BUC5kZm0kcHViZGF0ZSwgZm9ybWF0PSIlWS0lbS0lZCIpCmV4dHJlbV9BcC5kZm0kcHVieWVhciA8LSB5ZWFyKGV4dHJlbV9BUC5kZm0kcHViZGF0ZSkKCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUsIHRvU3RyaW5nKQojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlID0gbGFwcGx5KGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlLCB0b2xvd2VyKQojIAojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYWZ0ZXIgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciwgdG9TdHJpbmcpCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciA9IGxhcHBseShleHRyZW1fTllULmRmbSRDb250ZXh0LmFmdGVyLCB0b2xvd2VyKQoKZXh0cmVtX0FQLmRmbSA8LSBleHRyZW1fQVAuZGZtICU+JSBkaXN0aW5jdChDb250ZXh0LmJlZm9yZSwgLmtlZXBfYWxsID0gVFJVRSkKCmV4dHJlbV9BUC5kZm0ubG9uZyA8LSBwaXZvdF9sb25nZXIoZXh0cmVtX0FQLmRmbSwgY29scz1jKENvbnRleHQuYmVmb3JlLCBDb250ZXh0LmFmdGVyKSwgbmFtZXNfdG8gPSAiQ29udGV4dCIsIHZhbHVlc190byA9ICJjb250ZXh0LnRleHQiKQoKZXh0cmVtX0FQLmRmbS5sb25nJENvbnRleHQgPC0gYXMuZmFjdG9yKGV4dHJlbV9BUC5kZm0ubG9uZyRDb250ZXh0KQoKZXh0cmVtZWNvcnB1cyA8LXRleHRfY2xlYW5lcihleHRyZW1fQVAuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKYGBgCgoKQ2FsY3VsYXRlIEZXLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwplIDwtIGRmbShleHRyZW1lY29ycHVzJGNvbnRlbnQpCm1lc3NhZ2UoZGltKGUpKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgplIDwtIGRmbV9zZWxlY3QoZSwgcGF0dGVybiA9IHN0b3B3b3JkcygiZW5nbGlzaCIpLCBzZWxlY3Rpb24gPSAicmVtb3ZlIikKZSA8LSBkZm1fc2VsZWN0KGUsIG1pbl9uY2hhciA9IDIpCmUgPC0gZGZtX3RyaW0oZSwgbWluX3Rlcm1mcmVxID0gMTAwLCBtaW5fZG9jZnJlcSA9IC4wNSwgdmVyYm9zZT1UUlVFKQoKbWVzc2FnZShkaW0oZSkpCm1lc3NhZ2Uoc3BhcnNpdHkoZSkpCnNwYXJzaXR5KGUpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmV4dHJlbV9kdG0gPC0gY29udmVydChlLCB0bz0nZGF0YS5mcmFtZScpCmV4dHJlbV9kdG0gPC0gZXh0cmVtX2R0bVstYygxKV0KdyA8LSB3aGljaCggc2FwcGx5KGV4dHJlbV9kdG0sIGNsYXNzICkgPT0gJ2NoYXJhY3RlcicgKQoKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpmdy5leHRyZW0gPC0gZndncm91cHMoZXh0cmVtX2R0bSwgZ3JvdXBzPWV4dHJlbV9BUC5kZm0ubG9uZyRDb250ZXh0KQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgptZXNzYWdlKHJtKGV4dHJlbV9kdG0pKQptZXNzYWdlKHJtKGUpKQoKYGBgCgoKR2V0IGFuZCBzaG93IHRoZSB0b3Agd29yZHMgcGVyIGdyb3VwIGJ5IHpldGEuCgpgYGB7ciBlY2hvPVRSVUV9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKZndrZXlzLmV4dHJlbSA8LSBmdy5rZXlzKGZ3LmV4dHJlbSwgbi5rZXlzPTIwKQpjb2xzIDwtIHJldihjb2xuYW1lcyhmd2tleXMuZXh0cmVtKSkKZndrZXlzLmV4dHJlbSA8LSBmd2tleXMuZXh0cmVtWyxjb2xzXQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgprYWJsZShmd2tleXMuZXh0cmVtKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCipQbG90OiBDb21wYXJpbmcgV29yZHMgQmVmb3JlIChpbiBCbHVlKSwgYW5kIEFmdGVyIChpbiBSZWQpKgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTR9CnAuZncuZXh0cmVtIDwtIGZ3LmdncGxvdC5ncm91cHMoZncuZXh0cmVtLHNpemVzY2FsZT00LG1heC53b3Jkcz0yMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmNvdW50cmFuaz00MDAsY29sb3JwYWxldHRlPWMoInJlZCIsImJsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAnQ29tcGFyaXNvbiBvZiBUZXJtcyBCZWZvcmUgYW5kIEFmdGVyICJFeHRyZW1pc3QiJykKcC5mdy5leHRyZW0KCmBgYAoKIyMgQ2FsY3VsYXRlIFBhcnRzIG9mIHNwZWVjaCBieSBiZWZvcmUgYW5kIGFmdGVyCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKdWRfbW9kZWwgPC0gdWRwaXBlX2xvYWRfbW9kZWwodWRfbW9kZWwkZmlsZV9tb2RlbCkKCnR4dCA8LWFzLmNoYXJhY3RlcihleHRyZW1fQVAuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKeF91ZHAgPC0gdWRwaXBlX2Fubm90YXRlKHVkX21vZGVsLCB4ID0gdHh0LCBkb2NfaWQgPSBzZXFfYWxvbmcodHh0KSkKeCA8LSBhcy5kYXRhLmZyYW1lKHhfdWRwKQoKeCRkb2NfaWQgPC1hcy5pbnRlZ2VyKHgkZG9jX2lkKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCmBgYAoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnhfb2RkLmJlZm9yZSA8LSB4W3gkZG9jX2lkICUlIDIgPT0gMSxdCnhfZXZlbi5hZnRlciA8LXhbeCRkb2NfaWQgJSUgMiA9PSAwLCBdCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmBgYAoKYGBge3IgYmFyY2hhcnRmdW5jdHMsIGVjaG89RkFMU0V9CgojIyBVTklWRVJTQUwgUG9TClVQT1NfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSB0eHRfZnJlcShkZjEkdXBvcykKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleSkpCiAgCiAgc3RhdHMyIDwtIHR4dF9mcmVxKGRmMiR1cG9zKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBzdGF0czEsIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICBtYWluID0gIlVQT1MgKFVuaXZlcnNhbCBQYXJ0cyBvZiBTcGVlY2gpXG4gZnJlcXVlbmN5IG9mIG9jY3VycmVuY2U6IEJFRk9SRSB2cyBBRlRFUiIsIAogICAgICAgICB4bGFiID0gIkZyZXEiKSwgCiAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gc3RhdHMyLCBjb2wgPSAgJ3NreWJsdWUnLAogICAgICAgICB4bGFiID0gIkZyZXEiKSkKCn0KCgojIyBOT1VOUwpOT1VOU19iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgc3RhdHMxIDwtIHN1YnNldChkZjEsIHVwb3MgJWluJSBjKCJOT1VOIikpIAogIHN0YXRzMSA8LSB0eHRfZnJlcShzdGF0czEkdG9rZW4pCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiTk9VTiIpKSAKICBzdGF0czIgPC0gdHh0X2ZyZXEoc3RhdHMyJHRva2VuKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJNb3N0IG9jY3VycmluZyBub3VuczogQkVGT1JFIHZzIEFGVEVSIiwgeGxhYiA9ICJGcmVxIiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMiwgMjApLCBjb2wgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICB4bGFiID0gIkZyZXEiKSkKfQoKIyMgQURKRUNUSVZFUwpBREpfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSBzdWJzZXQoZGYxLCB1cG9zICVpbiUgYygiQURKIikpIAogIHN0YXRzMSA8LSB0eHRfZnJlcShzdGF0czEkdG9rZW4pCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiQURKIikpIAogIHN0YXRzMiA8LSB0eHRfZnJlcShzdGF0czIkdG9rZW4pCiAgc3RhdHMyJGtleSA8LSBmYWN0b3Ioc3RhdHMyJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXkpKQogIAogIGMoYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMxLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIk1vc3Qgb2NjdXJyaW5nIGFkamVjdGl2ZXM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcSIpLAogICAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czIsIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgeGxhYiA9ICJGcmVxIikpCn0KCiMjIFVzaW5nIFJBS0UgdG8gZmluZCBrZXl3b3JkcwpSQUtFX0tXX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSxkZjIpewogIAogIHN0YXRzMSA8LSBrZXl3b3Jkc19yYWtlKHggPSBkZjEsIHRlcm0gPSAibGVtbWEiLCBncm91cCA9ICJkb2NfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW50ID0gZGYxJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleXdvcmQpKQogIAogIHN0YXRzMiA8LSBrZXl3b3Jkc19yYWtlKHggPSBkZjIsIHRlcm0gPSAibGVtbWEiLCBncm91cCA9ICJkb2NfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW50ID0gZGYyJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleXdvcmQpKQogIAogIAogIGMoYmFyY2hhcnQoa2V5IH4gcmFrZSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMSwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIGlkZW50aWZpZWQgYnkgUkFLRTogQkVGT1JFIHZzIEFGVEVSIiwgCiAgICAgICAgICAgeGxhYiA9ICJSYWtlIiksCiAgICBiYXJjaGFydChrZXkgfiByYWtlLCBkYXRhID0gaGVhZChzdWJzZXQoc3RhdHMyLCBmcmVxID4gMyksIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICB4bGFiID0gIlJha2UiKSkKfQoKIyMgVXNpbmcgUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbiBDb2xsb2NhdGlvbnMKUFdJX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBkZjEkd29yZCA8LSB0b2xvd2VyKGRmMSR0b2tlbikKICBzdGF0czEgPC0ga2V5d29yZHNfY29sbG9jYXRpb24oeCA9IGRmMSwgdGVybSA9ICJ3b3JkIiwgZ3JvdXAgPSAiZG9jX2lkIikKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBkZjIkd29yZCA8LSB0b2xvd2VyKGRmMiR0b2tlbikKICBzdGF0czIgPC0ga2V5d29yZHNfY29sbG9jYXRpb24oeCA9IGRmMiwgdGVybSA9ICJ3b3JkIiwgZ3JvdXAgPSAiZG9jX2lkIikKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IHBtaSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMSwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIGlkZW50aWZpZWQgYnkgUE1JIENvbGxvY2F0aW9uOiBCRUZPUkUgdnMgQUZURVIiLCAKICAgICAgICAgICB4bGFiID0gIlBNSSAoUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbikiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gcG1pLCBkYXRhID0gaGVhZChzdWJzZXQoc3RhdHMyLCBmcmVxID4gMyksIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICB4bGFiID0gIlBNSSAoUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbikiKSkKfQoKIyMgVXNpbmcgYSBzZXF1ZW5jZSBvZiBQT1MgdGFncyAobm91biBwaHJhc2VzIC8gdmVyYiBwaHJhc2VzKQpQT1NfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIGRmMSRwaHJhc2VfdGFnIDwtIGFzX3BocmFzZW1hY2hpbmUoZGYxJHVwb3MsIHR5cGUgPSAidXBvcyIpCiAgc3RhdHMxIDwtIGtleXdvcmRzX3BocmFzZXMoeCA9IGRmMSRwaHJhc2VfdGFnLCB0ZXJtID0gdG9sb3dlcihkZjEkdG9rZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKEF8TikqTihQK0QqKEF8TikqTikqIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc19yZWdleCA9IFRSVUUsIGRldGFpbGVkID0gRkFMU0UpCiAgc3RhdHMxIDwtIHN1YnNldChzdGF0czEsIG5ncmFtID4gMSAmIGZyZXEgPiAzKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleXdvcmQpKQogIAogIGRmMiRwaHJhc2VfdGFnIDwtIGFzX3BocmFzZW1hY2hpbmUoZGYyJHVwb3MsIHR5cGUgPSAidXBvcyIpCiAgc3RhdHMyIDwtIGtleXdvcmRzX3BocmFzZXMoeCA9IGRmMiRwaHJhc2VfdGFnLCB0ZXJtID0gdG9sb3dlcihkZjIkdG9rZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKEF8TikqTihQK0QqKEF8TikqTikqIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc19yZWdleCA9IFRSVUUsIGRldGFpbGVkID0gRkFMU0UpCiAgc3RhdHMyIDwtIHN1YnNldChzdGF0czIsIG5ncmFtID4gMSAmIGZyZXEgPiAzKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleXdvcmQpKQogIAogIGMoYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMxLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIC0gc2ltcGxlIG5vdW4gcGhyYXNlczogQkVGT1JFIHZzIEFGVEVSIiwgeGxhYiA9ICJGcmVxdWVuY3kiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMyLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgICAgIHhsYWIgPSAiRnJlcXVlbmN5IikpCn0KYGBgCgoKIyMgQmFyIENoYXJ0cyBmb3IgUGFydHMgb2YgU3BlZWNoIAoKYGBge3IgUE9TYmFyY2hhcnRzLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9OH0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpVUE9TX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpOT1VOU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKQURKX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpSQUtFX0tXX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpQV0lfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKClBPU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpgYGAKCgojIyBDb29jY3VyZW5jZXMKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9Nn0KCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5iZWZvcmUgPC0gZnVuY3Rpb24oZGYxKXsKICAKICBsaWJyYXJ5KGlncmFwaCkKICBsaWJyYXJ5KGdncmFwaCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChkZjEsIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQoKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICAKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAicGluayIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICAgIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQogIAp9CgpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYWZ0ZXIgPC0gZnVuY3Rpb24oZGYyKXsKICAKICBsaWJyYXJ5KGlncmFwaCkKICBsaWJyYXJ5KGdncmFwaCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChkZjIsIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQoKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICAKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAibGlnaHRncmVlbiIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2JsdWUiLCBzaXplID0gNCkgKwogICAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBsYWJzKHRpdGxlID0gIkNvb2NjdXJyZW5jZXMgd2l0aGluIHNlbnRlbmNlOiBBRlRFUiIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIikKICAKfQoKCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5iZWZvcmUoeF9vZGQuYmVmb3JlKQpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYWZ0ZXIoeF9ldmVuLmFmdGVyKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmJlZm9yZSA8LSBmdW5jdGlvbihkZil7CiAgY29vYyA8LSBjb29jY3VycmVuY2UoZGYkbGVtbWEsIHJlbGV2YW50ID0gZGYkdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIiksIHNraXBncmFtID0gMSkKICBoZWFkKGNvb2MpCiAgCiAgd29yZG5ldHdvcmsgPC0gaGVhZChjb29jLCA2MCkKICB3b3JkbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUod29yZG5ldHdvcmspCiAgZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gImxpZ2h0Z3JlZW4iKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtncmVlbiIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICBsYWJzKHRpdGxlID0gIldvcmRzIGZvbGxvd2luZyBvbmUgYW5vdGhlcjogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQp9CgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYWZ0ZXIgPC0gZnVuY3Rpb24oZGYpewogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGRmJGxlbW1hLCByZWxldmFudCA9IGRmJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgaGVhZChjb29jKQogIAogIHdvcmRuZXR3b3JrIDwtIGhlYWQoY29vYywgNjApCiAgd29yZG5ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHdvcmRuZXR3b3JrKQogIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJza3libHVlIikgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrYmx1ZSIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICBsYWJzKHRpdGxlID0gIldvcmRzIGZvbGxvd2luZyBvbmUgYW5vdGhlcjogQUZURVIiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSIpCn0KCgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYmVmb3JlKHhfb2RkLmJlZm9yZSkKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmFmdGVyKHhfZXZlbi5hZnRlcikKCmBgYAoKCgojIyBDb29jY3VyZW5jZXMgKHBhcnQgMikKCmBgYHtyLCBlY2hvPUZBTFNFfQoKQ29ycnMgPC0gZnVuY3Rpb24oZGYpewogIGRmJGlkIDwtIHVuaXF1ZV9pZGVudGlmaWVyKGRmLCBmaWVsZHMgPSBjKCJzZW50ZW5jZV9pZCIsICJkb2NfaWQiKSkKICBkdG0gPC0gc3Vic2V0KGRmLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBkdG0gPC0gZG9jdW1lbnRfdGVybV9mcmVxdWVuY2llcyhkdG0sIGRvY3VtZW50ID0gImlkIiwgdGVybSA9ICJsZW1tYSIpCiAgZHRtIDwtIGRvY3VtZW50X3Rlcm1fbWF0cml4KGR0bSkKICBkdG0gPC0gZHRtX3JlbW92ZV9sb3dmcmVxKGR0bSwgbWluZnJlcSA9IDUpCiAgdGVybWNvcnJlbGF0aW9ucyA8LSBkdG1fY29yKGR0bSkKICB5IDwtIGFzX2Nvb2NjdXJyZW5jZSh0ZXJtY29ycmVsYXRpb25zKQogIHkgPC0gc3Vic2V0KHksIHRlcm0xIDwgdGVybTIgJiBhYnMoY29vYykgPiAwLjIpCiAgeSA8LSB5W29yZGVyKGFicyh5JGNvb2MpLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KICB5WzE6MjUsXQp9CgpgYGAKCmBgYHtyfQoKQ29ycnMoeF9vZGQuYmVmb3JlKQpDb3Jycyh4X2V2ZW4uYWZ0ZXIpCgpgYGAKCgojIEV4dHJlbShpc3QpIEZpZ2h0aW4nIFdvcmRzIE92ZXIgVGltZQpgYGB7cn0KbGlicmFyeSh0d2VlbnIpCgpUcmFuc2l0aW9uVGltZTIgPC0gZ2dwcm90bygKICAiVHJhbnNpdGlvblRpbWUyIiwKICBUcmFuc2l0aW9uVGltZSwKICBleHBhbmRfcGFuZWwgPSBmdW5jdGlvbiAoc2VsZiwgZGF0YSwgdHlwZSwgaWQsIG1hdGNoLCBlYXNlLCBlbnRlciwgZXhpdCwgcGFyYW1zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXJfaW5kZXgpIHsKICAgIHJvd190aW1lIDwtIHNlbGYkZ2V0X3Jvd192YXJzKGRhdGEpCiAgICBpZiAoaXMubnVsbChyb3dfdGltZSkpIAogICAgICByZXR1cm4oZGF0YSkKICAgIGRhdGEkZ3JvdXAgPC0gcGFzdGUwKHJvd190aW1lJGJlZm9yZSwgcm93X3RpbWUkYWZ0ZXIpCiAgICB0aW1lIDwtIGFzLmludGVnZXIocm93X3RpbWUkdGltZSkKICAgIHN0YXRlcyA8LSBzcGxpdChkYXRhLCB0aW1lKQogICAgdGltZXMgPC0gYXMuaW50ZWdlcihuYW1lcyhzdGF0ZXMpKQogICAgbmZyYW1lcyA8LSBkaWZmKHRpbWVzKQogICAgbmZyYW1lc1sxXSA8LSBuZnJhbWVzWzFdICsgMQogICAgaWYgKHRpbWVzWzFdIDw9IDEpIHsKICAgICAgYWxsX2ZyYW1lcyA8LSBzdGF0ZXNbWzFdXQogICAgICBzdGF0ZXMgPC0gc3RhdGVzWy0xXQogICAgfQogICAgZWxzZSB7CiAgICAgIGFsbF9mcmFtZXMgPC0gZGF0YVswLCAsIGRyb3AgPSBGQUxTRV0KICAgICAgbmZyYW1lcyA8LSBjKHRpbWVzWzFdIC0gMSwgbmZyYW1lcykKICAgIH0KICAgIGlmICh0aW1lc1tsZW5ndGgodGltZXMpXSA8IHBhcmFtcyRuZnJhbWVzKSB7CiAgICAgIHN0YXRlcyA8LSBjKHN0YXRlcywgbGlzdChkYXRhWzAsICwgZHJvcCA9IEZBTFNFXSkpCiAgICAgIG5mcmFtZXMgPC0gYyhuZnJhbWVzLCBwYXJhbXMkbmZyYW1lcyAtIHRpbWVzW2xlbmd0aCh0aW1lcyldKQogICAgfQogICAgZm9yIChpIGluIHNlcV9hbG9uZyhzdGF0ZXMpKSB7CiAgICAgIGFsbF9mcmFtZXMgPC0gc3dpdGNoKHR5cGUsIHBvaW50ID0gdHdlZW5fc3RhdGUoYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGVzW1tpXV0sIGVhc2UsIG5mcmFtZXNbaV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEhaWQsIGVudGVyLCBleGl0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGggPSB0cmFuc2Zvcm1fcGF0aChhbGxfZnJhbWVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlc1tbaV1dLCBlYXNlLCBuZnJhbWVzW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEhaWQsIGVudGVyLCBleGl0LCBtYXRjaCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwb2x5Z29uID0gdHJhbnNmb3JtX3BvbHlnb24oYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZXNbW2ldXSwgZWFzZSwgbmZyYW1lc1tpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhIWlkLCBlbnRlciwgZXhpdCwgbWF0Y2gpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2YgPSB0cmFuc2Zvcm1fc2YoYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlc1tbaV1dLCBlYXNlLCBuZnJhbWVzW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgISFpZCwgZW50ZXIsIGV4aXQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCh0eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIGxheWVycyBub3QgY3VycmVudGx5IHN1cHBvcnRlZCBieSB0cmFuc2l0aW9uX3RpbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxsLiA9IEZBTFNFKSkKICAgIH0KICAgIHRydWVfZnJhbWUgPC0gc2VxKHRpbWVzWzFdLCB0aW1lc1tsZW5ndGgodGltZXMpXSkKICAgIGFsbF9mcmFtZXMgPC0gYWxsX2ZyYW1lc1sKICAgICAgYWxsX2ZyYW1lcyQuZnJhbWUgJWluJSAKICAgICAgICAjIHdoaWNoKHRydWVfZnJhbWUgPiAwICYgdHJ1ZV9mcmFtZSA8PSBwYXJhbXMkbmZyYW1lcyksCiAgICAgICAgdHJ1ZV9mcmFtZVt3aGljaCh0cnVlX2ZyYW1lID4gMCAmIHRydWVfZnJhbWUgPD0gcGFyYW1zJG5mcmFtZXMpXSwgIyB0d2VhayBsaW5lIEEKICAgICAgLCAKICAgICAgZHJvcCA9IEZBTFNFXQogICAgIyBhbGxfZnJhbWVzJC5mcmFtZSA8LSBhbGxfZnJhbWVzJC5mcmFtZSAtIG1pbihhbGxfZnJhbWVzJC5mcmFtZSkgKyAxICMgcmVtb3ZlIGxpbmUgQgogICAgYWxsX2ZyYW1lcyRncm91cCA8LSBwYXN0ZTAoYWxsX2ZyYW1lcyRncm91cCwgIjwiLCBhbGxfZnJhbWVzJC5mcmFtZSwgIj4iKQogICAgYWxsX2ZyYW1lcyQuZnJhbWUgPC0gTlVMTAogICAgYWxsX2ZyYW1lcwogIH0pCgp0cmFuc2l0aW9uX3RpbWUyIDwtIGZ1bmN0aW9uICh0aW1lLCByYW5nZSA9IE5VTEwpIHsKICB0aW1lX3F1byA8LSBlbnF1byh0aW1lKQogIGdnYW5pbWF0ZTo6OnJlcXVpcmVfcXVvKHRpbWVfcXVvLCAidGltZSIpCiAgZ2dwcm90byhOVUxMLCBUcmFuc2l0aW9uVGltZTIsIAogICAgICAgICAgcGFyYW1zID0gbGlzdCh0aW1lX3F1byA9IHRpbWVfcXVvLCByYW5nZSA9IHJhbmdlKSkKfQpgYGAKCmBgYHtyIGV4dHJhX2xvYWRzX29kZF9iZWZvcmUsIGZpZy53aWR0aD0xMH0KbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoZ2dmb3JjZSkKbGlicmFyeShnZ2FuaW1hdGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkoYW5pbWF0aW9uKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCgpyZXN1bHRzPC1tZXJnZSh4PXgseT1leHRyZW1fQVAuZGZtLmxvbmcsIGJ5Lng9J2RvY19pZCcsICBieS55ID0gMCAgLGFsbC54PVRSVUUpCnJlc3VsdHNfb2RkLmJlZm9yZSA8LSByZXN1bHRzW3Jlc3VsdHMkZG9jX2lkICUlIDIgPT0gMSxdCnJlc3VsdHNfZXZlbi5hZnRlciA8LXJlc3VsdHNbcmVzdWx0cyRkb2NfaWQgJSUgMiA9PSAwLCBdCgpjb29jX3llYXI8LSBkYXRhLmZyYW1lKCkKCmZvcih5IGluIHVuaXF1ZShyZXN1bHRzX29kZC5iZWZvcmUkcHVieWVhcikpewogIHByaW50KHkpCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChmaWx0ZXIocmVzdWx0c19vZGQuYmVmb3JlLCBwdWJ5ZWFyID09IHkpLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSksIAogICAgICAgICAgICAgICAgICAgICAgIHRlcm0gPSAibGVtbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMoImRvY19pZCIsICJwYXJhZ3JhcGhfaWQiLCAic2VudGVuY2VfaWQiKSkKICBjb29jJHllYXIgPC0geQogIGNvb2M8LSBoZWFkKGNvb2MsIDE0KQogIGNvb2NfeWVhciA8LSByYmluZChjb29jX3llYXIsIGNvb2MpCn0KCmRpbShjb29jX3llYXIpCndvcmRuZXR3b3JrIDwtIGNvb2NfeWVhcgoKcDwtIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAicGluayIpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtncmVlbiIsIHNpemUgPSA0KSArCiAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICMgZmFjZXRfd3JhcF9wYWdpbmF0ZSh+eWVhcikrCiAgc2NhbGVfYWxwaGFfaWRlbnRpdHkoKSsKICBsYWJzKHRpdGxlID0gIkNvb2NjdXJyZW5jZXMgd2l0aGluIHNlbnRlbmNlOiBCRUZPUkUiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSB7ZnJhbWVfdGltZX0iKSsKICB0cmFuc2l0aW9uX3RpbWUyKHllYXIpCiAgZWFzZV9hZXMoJ2xpbmVhcicpCgpwCnBsb3QocCkKIyBsYXN0X2FuaW1hdGlvbigpCgpgYGAKYGBge3IgZXh0cmFfbG9hZHNfZXZlbl9hZnRlciwgZmlnLndpZHRoPTEwfQoKY29vY195ZWFyPC0gZGF0YS5mcmFtZSgpCgpmb3IoeSBpbiB1bmlxdWUocmVzdWx0c19ldmVuLmFmdGVyJHB1YnllYXIpKXsKICBwcmludCh5KQogIGNvb2MgPC0gY29vY2N1cnJlbmNlKHggPSBzdWJzZXQoZmlsdGVyKHJlc3VsdHNfZXZlbi5hZnRlciwgcHVieWVhciA9PSB5KSwgdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIikpLCAKICAgICAgICAgICAgICAgICAgICAgICB0ZXJtID0gImxlbW1hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBjKCJkb2NfaWQiLCAicGFyYWdyYXBoX2lkIiwgInNlbnRlbmNlX2lkIikpCiAgY29vYyR5ZWFyIDwtIHkKICBjb29jPC0gaGVhZChjb29jLCAxNCkKICBjb29jX3llYXIgPC0gcmJpbmQoY29vY195ZWFyLCBjb29jKQp9CgpkaW0oY29vY195ZWFyKQp3b3JkbmV0d29yayA8LSBjb29jX3llYXIKCnAyPC0gZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKcDIKcGxvdChwMikKIyBsYXN0X2FuaW1hdGlvbigpCgpgYGAKCmBgYHtyIGNvb2MyX2JlZm9yZSwgZmlnLndpZHRoPTEwfQoKY29vYzJfeWVhcjwtIGRhdGEuZnJhbWUoKQoKZm9yKHkgaW4gdW5pcXVlKHJlc3VsdHNfb2RkLmJlZm9yZSRwdWJ5ZWFyKSl7CiAgcHJpbnQoeSkKICBhPC0gZmlsdGVyKHJlc3VsdHNfb2RkLmJlZm9yZSwgcHVieWVhciA9PSB5KQogIAogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGEkbGVtbWEsIHJlbGV2YW50ID0gYSR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSwgc2tpcGdyYW0gPSAxKQogIGNvb2MkeWVhciA8LSB5CiAgY29vYzwtIGhlYWQoY29vYywgMjUpCiAgY29vYzJfeWVhciA8LSByYmluZChjb29jMl95ZWFyLCBjb29jKQp9CgoKZGltKGNvb2MyX3llYXIpCndvcmRuZXR3b3JrIDwtIGNvb2MyX3llYXIKCnAzPC0gZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEJFRk9SRSIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIHtmcmFtZV90aW1lfSIpKwogIHRyYW5zaXRpb25fdGltZTIoeWVhcikKICBlYXNlX2FlcygnbGluZWFyJykKCnAzCnBsb3QocDMpCiMgbGFzdF9hbmltYXRpb24oKQoKYGBgCmBgYHtyIGNvb2MyX2FmdGVyLCBmaWcud2lkdGg9MTB9Cgpjb29jMl95ZWFyPC0gZGF0YS5mcmFtZSgpCgpmb3IoeSBpbiB1bmlxdWUocmVzdWx0c19ldmVuLmFmdGVyJHB1YnllYXIpKXsKICBwcmludCh5KQogIGE8LSBmaWx0ZXIocmVzdWx0c19ldmVuLmFmdGVyLCBwdWJ5ZWFyID09IHkpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoYSRsZW1tYSwgcmVsZXZhbnQgPSBhJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgY29vYyR5ZWFyIDwtIHkKICBjb29jPC0gaGVhZChjb29jLCAyNSkKICBjb29jMl95ZWFyIDwtIHJiaW5kKGNvb2MyX3llYXIsIGNvb2MpCn0KCgpkaW0oY29vYzJfeWVhcikKd29yZG5ldHdvcmsgPC0gY29vYzJfeWVhcgoKcDQ8LSBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gInBpbmsiKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrZ3JlZW4iLCBzaXplID0gNCkgKwogIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAjIGZhY2V0X3dyYXBfcGFnaW5hdGUofnllYXIpKwogIHNjYWxlX2FscGhhX2lkZW50aXR5KCkrCiAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQUZURVIiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSB7ZnJhbWVfdGltZX0iKSsKICB0cmFuc2l0aW9uX3RpbWUyKHllYXIpCiAgZWFzZV9hZXMoJ2xpbmVhcicpCgpwNApwbG90KHA0KQojIGxhc3RfYW5pbWF0aW9uKCkKCmBgYAoKCgoKYGBge3IgZmluYWwsIGVjaG89RkFMU0V9CgpybShsaXN0PWxzKCkpCgpgYGAKCgoKCgoKCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQo=